mod analysis;
mod bar_line_chart;
mod pie_chart;

use bar_line_chart::create_bar_line_chart;
use pie_chart::create_pie_chart;
use redis::Commands;
use serde_json::Value;
use shq_common::prelude::{get_ch_pool, get_redis_cli, report::Unit, DataType, FieldType};

use crate::{database::query_to_list,Column};

pub struct ExecutorFunc<'a> {
    name: &'a str,
}
impl<'a> ExecutorFunc<'a> {
    pub fn new(name: &'a str) -> Self {
        Self { name }
    }
    pub async fn exec(
        &self,
        rept_name: &str,
        params: &[(&str, &str)],
        leaf_cols: &[&Column],
        rept_unit: &Unit,
        tmp_table_name: &str,
    ) -> anyhow::Result<()> {
        match self.name {
            "create_bar_line_chart" => {
                create_bar_line_chart(rept_name, params, leaf_cols, rept_unit, tmp_table_name).await
            }
            "create_pie_chart" => {
                create_pie_chart(rept_name, params, leaf_cols, rept_unit, tmp_table_name).await
            }
            "create_analysis_dept1" => {
                analysis::create_analysis_dept1(rept_name, params, tmp_table_name).await
            }
            "create_analysis_dept2" => {
                analysis::create_analysis_dept2(rept_name, params, tmp_table_name).await
            }
            "create_analysis_empl" => {
                analysis::create_analysis_empl(rept_name, params, tmp_table_name).await
            }
            "create_analysis_comp_clie" => {
                analysis::create_analysis_comp_clie(rept_name, params, tmp_table_name).await
            }
            "create_analysis_indi_clie" => {
                analysis::create_analysis_indi_clie(rept_name, params, tmp_table_name).await
            }
            _ => Err(anyhow::anyhow!("没有找到ExecutorFunc:{}", self.name)),
        }
    }
}
pub(crate) static REPT_DATAS: &str = "report_datas";
pub(crate) static REPT_DATAS_COLS: &str = "report_datas_cols";
pub(crate) struct RedisCache<'a> {
    rcli: redis::Connection,
    tmp_table_name: &'a str,
}
impl<'a> RedisCache<'a> {
    pub(crate) fn new(tmp_table_name: &'a str) -> anyhow::Result<Self> {
        let rcli = get_redis_cli().get_connection()?;
        Ok(Self {
            rcli,
            tmp_table_name,
        })
    }
    pub(crate) async fn cache(
        &mut self,
        sql_str: &str,
        leafs: &[&Column],
        rept_unit: &Unit,
    ) -> anyhow::Result<()> {
        let mut client = get_ch_pool().get_handle().await?;
        let (datas, types) = query_to_list(&mut client, sql_str, leafs, &rept_unit).await?;
        let name_col_types: Vec<(String, FieldType)> = types
            .into_iter()
            .enumerate()
            .map(|(i, st)| (leafs[i].name.clone().unwrap(), st.into()))
            .collect();
        let _: () = self.rcli.hset(
            REPT_DATAS,
            self.tmp_table_name,
            serde_json::to_string(&datas)?,
        )?;
        let _: () = self.rcli.hset(
            REPT_DATAS_COLS,
            self.tmp_table_name,
            serde_json::to_string(&name_col_types)?,
        )?;
        Ok(())
    }
    pub(crate) fn is_exist(&mut self) -> anyhow::Result<bool> {
        let is_exist: bool = self.rcli.hexists(REPT_DATAS, self.tmp_table_name)?;
        Ok(is_exist)
    }
    pub(crate) fn get(&mut self) -> anyhow::Result<Vec<Vec<Value>>> {
        let data_str: Option<String> = self.rcli.hget(REPT_DATAS, self.tmp_table_name)?;
        let data_str = data_str.ok_or(anyhow::anyhow!(
            "{}数据不在Redis缓存中",
            self.tmp_table_name
        ))?;
        let datas: Vec<Vec<Value>> = serde_json::from_str(data_str.as_str())?;
        Ok(datas)
    }
    pub(crate) fn get_columns(&mut self) -> anyhow::Result<Vec<(String, DataType)>> {
        let data_str: Option<String> = self.rcli.hget(REPT_DATAS_COLS, self.tmp_table_name)?;
        let data_str = data_str.ok_or(anyhow::anyhow!(
            "{}数据不在Redis缓存中",
            self.tmp_table_name
        ))?;
        let types: Vec<(String, DataType)> = serde_json::from_str(data_str.as_str())?;
        Ok(types)
    }
    pub(crate) fn del(&mut self) -> anyhow::Result<bool> {
        let is_del: bool = self.rcli.hdel(REPT_DATAS, self.tmp_table_name)?;
        if is_del {
            let _: () = self.rcli.hdel(REPT_DATAS_COLS, self.tmp_table_name)?;
        }
        Ok(is_del)
    }
}
